import Flutter
import UIKit
import QCloudCOSXML
import QCloudCore

public class SwiftTencentCosPlugin: NSObject, FlutterPlugin, QCloudSignatureProvider, QCloudCredentailFenceQueueDelegate {
    private var credentialFenceQueue:QCloudCredentailFenceQueue?
    private var mBucket: String = ""
    private var mAppID: String = ""
    private var mSignUrl: String = ""
    private var mCookie: String = ""
    private var mRegion: String = ""

    public func signature(with fileds: QCloudSignatureFields!, request: QCloudBizHTTPRequest!, urlRequest urlRequst: NSMutableURLRequest!, compelete continueBlock: QCloudHTTPAuthentationContinueBlock!) {
        self.credentialFenceQueue?.performAction({ (creator, error) in
            if error != nil {
                continueBlock(nil,error!);
            }else{
                let signature = creator?.signature(forData: urlRequst);
                continueBlock(signature,nil);
            }
        })
    }

    public func fenceQueue(_ queue: QCloudCredentailFenceQueue!, requestCreatorWithContinue continueBlock: QCloudCredentailFenceQueueContinue!) {
        let request: QCloudHTTPRequest = QCloudHTTPRequest.init()
        request.requestSerializer.httpMethod = HTTPMethodPOST
        request.requestSerializer.useCookies = false
        request.requestSerializer.shouldAuthentication = false

        request.requestData.serverURL = self.mSignUrl
        request.requestData.setValue(self.mCookie, forHTTPHeaderField: "authorization")
        request.requestData.setParameter(self.mBucket, withKey: "bucket")
        request.requestData.setParameter(self.mRegion, withKey: "region")

        request.setConfigureBlock { (_ requestSerializer: QCloudRequestSerializer, _ responseSerializer: QCloudResponseSerializer) in
            requestSerializer.serializerBlocks = [QCloudURLFuseSimple, QCloudURLFuseWithJSONParamters]
            responseSerializer.serializerBlocks = [QCloudAcceptRespnseCodeBlock([200], nil), QCloudResponseJSONSerilizerBlock]
        }

        QCloudHTTPSessionManager.shareClient()?.perform(request, withFinish: { (_ response: Any?, _ error: Error?) in
            if(error != nil) {
                continueBlock(nil, error)
            } else {
                let dic:Dictionary = response! as! Dictionary<String, Any>
                let code = dic["status"] as! Int
                if(code == 0) {
                    let data: Dictionary = dic["data"] as! Dictionary<String, Any>
                    let credentialData: Dictionary = data["credentials"] as! Dictionary<String, String>
                    let cre = QCloudCredential.init();
                    cre.secretID = credentialData["tmpSecretId"];
                    cre.secretKey = credentialData["tmpSecretKey"];
                    cre.token = credentialData["sessionToken"];
                    cre.experationDate = DateFormatter().date(from: "\(data["expiredTime"] as! Int)")
                    let auth = QCloudAuthentationV5Creator.init(credential: cre);
                    continueBlock(auth,nil);
                } else {
                    continueBlock(nil, NSError.init(domain: self.mSignUrl, code: code, userInfo: nil))
                }
            }
        })
    }

    public static func register(with registrar: FlutterPluginRegistrar) {
        let channel = FlutterMethodChannel(name: "tencent_cos", binaryMessenger: registrar.messenger())
        let instance = SwiftTencentCosPlugin()
        registrar.addMethodCallDelegate(instance, channel: channel)
    }

    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        switch call.method {
            case "getPlatformVersion":
                result("iOS " + UIDevice.current.systemVersion)
            case "initCosServer":
                initCosServer(call, result: result)
            case "upload":
              upload(call, result: result)
            default:
                result (FlutterMethodNotImplemented)
        }
    }

    private func initCosServer(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let args: NSDictionary = call.arguments as! NSDictionary

        mBucket = args["bucket"] as! String
        mAppID = args["appID"] as! String
        mSignUrl = args["signUrl"] as! String
        mCookie = args["cookie"] as! String
        mRegion = args["region"] as! String

        let config = QCloudServiceConfiguration.init();
        config.appID = mAppID
        config.signatureProvider = self
        let endPoint = QCloudCOSXMLEndPoint.init()
        endPoint.regionName = mRegion
        endPoint.useHTTPS = false
        config.endpoint = endPoint
        QCloudCOSXMLService.registerDefaultCOSXML(with: config)
        QCloudCOSTransferMangerService.registerDefaultCOSTransferManger(with: config)
        self.credentialFenceQueue = QCloudCredentailFenceQueue.init()
        self.credentialFenceQueue?.delegate = self
        #if targetEnvironment(simulator)
            result(1)
        #else
            TACMTAConfig.getInstance()?.debugEnable = true
            TACMTAConfig.getInstance()?.statEnable = false

            result(1)
        #endif
    }

    private func upload(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let args: NSDictionary = call.arguments as! NSDictionary
        let originLocalPath: String = args["localPath"] as! String
        let targetPath: String = args["cosPath"] as! String
        
        var index = originLocalPath.lastIndex(of: "/") ?? originLocalPath.startIndex
        if(index != originLocalPath.startIndex) {
            index = originLocalPath.index(after: index)
        }

        var fileName = originLocalPath[index..<originLocalPath.endIndex]
        print(fileName)

        let uploadRequest = QCloudCOSXMLUploadObjectRequest<AnyObject>.init();
        uploadRequest.bucket = mBucket + "-" + mAppID
        uploadRequest.object = targetPath + "\(Int(NSTimeIntervalSince1970))" + fileName
        uploadRequest.body = URL.init(fileURLWithPath: originLocalPath) as AnyObject

        uploadRequest.setFinish { (ret, error) in
        if error != nil{
            DispatchQueue.main.async {
              // Call the desired channel message here.
                result(error!.localizedDescription)
            }
        }else{
            DispatchQueue.main.async {
              // Call the desired channel message here.
                result((ret!).location);
            }
        }}

        QCloudCOSTransferMangerService.defaultCOSTransferManager().uploadObject(uploadRequest)
    }
}
